﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Nextropia.C2Manager.C2API
{
    /// <summary>
    /// indicates the signal or trade type order type
    /// </summary>
    public enum ActionType { 
        /// <summary>
        /// undefined
        /// </summary>
        Undefined, 

        /// <summary>
        /// Sell To Open; used to open a short positon (for futures, options, and forex only)
        /// </summary>
        /// <seealso cref="SSHORT"/>
        STO, 

        /// <summary>
        /// Sell Short; used to open a short position (for equities only)
        /// </summary>
        /// <seealso cref="STO"/>
        SSHORT, 

        /// <summary>
        /// Buy To Open; used to open a long position (all security types)
        /// </summary>
        BTO, 

        /// <summary>
        /// Sell To Close; used to close a long position
        /// </summary>
        STC, 

        /// <summary>
        /// Buy To Close; used to close a short position
        /// </summary>
        BTC };

    /// <summary>
    /// indicates the time in force for a signal
    /// </summary>
    public enum TimeInForce { 
        /// <summary>
        /// good for the day
        /// </summary>
        DAY, 

        /// <summary>
        /// good till cancelled
        /// </summary>
        GTC };

    /// <summary>
    /// indicates the security type
    /// </summary>
    public enum SecurityType { 
        /// <summary>
        /// future contract
        /// </summary>
        Future, 

        /// <summary>
        /// forex pair
        /// </summary>
        Forex, 

        /// <summary>
        /// equity
        /// </summary>
        Stock, 

        /// <summary>
        /// option contract
        /// </summary>
        Option };

    /// <summary>
    /// represents a trading signal
    /// </summary>
    public class Signal
    {
        /// <summary>
        /// the unique identifier of the signal on the C2 system
        /// </summary>
        public string ID{get;set;}

        /// <summary>
        /// the unique identifier of the trade associated with this signal
        /// </summary>
        public string TradeID { get; set; }

        /// <summary>
        /// the time when this signal was submitted
        /// </summary>
        public DateTime Posted{get;set;}

        /// <summary>
        /// the time when this signal was executed
        /// </summary>
        public DateTime Traded{get;set;}

        /// <summary>
        /// the order type for the signal
        /// </summary>
        public ActionType ActionType{get;set;}

        /// <summary>
        /// the quantity traded with this signal
        /// </summary>
        public decimal Quantity{get;set;}

        /// <summary>
        /// the symbol for which this signal was submitted
        /// </summary>
        public string Symbol{get;set;}

        /// <summary>
        /// the security type for which this signal was submitted
        /// </summary>
        public SecurityType SecurityType{get;set;}

        /// <summary>
        /// the limit price at which this signal should be executed; 0 if no limit (market order)
        /// </summary>
        public decimal Limit{get;set;}

        /// <summary>
        /// the stop price at which this signal should be executed; 0 if no stop (market order)
        /// </summary>        
        public decimal Stop{get;set;}

        /// <summary>
        /// the period for which this signal is valid
        /// </summary>
        public TimeInForce TimeInForce{get;set;}

        /// <summary>
        /// the price at which this signal was traded
        /// </summary>
        public decimal TradePrice{get;set;}

        /// <summary>
        /// any notes or commentary submitted by the system vendor along with this signal
        /// </summary>
        public string Comment{get;set;}

        /// <summary>
        /// indicates whether this signal will be executed at market (i.e. not a stop or limit order)
        /// </summary>
        public bool IsMarketOrder { get; set; }

        /// <summary>
        /// the system for which this signal was submitted
        /// </summary>
        public TradingSystem System { get; private set; }

        /// <summary>
        /// default constructor taking the parent TradingSystem as a parameter
        /// </summary>
        /// <remarks>
        /// the signal is NOT automatically added to the TradingSystem.PendingSignals collection
        /// </remarks>
        /// <seealso cref="TradingSystem.PendingSignals"/>
        /// <seealso cref="TradingSystem.ExecutedSignals"/>
        /// <param name="system"></param>
        public Signal(TradingSystem system)
        {
            System = system;
        }

        internal Signal(TradingSystem system, XmlNode sourceNode) : this(system)
        {
            //HACK: API returns different types of nodes for different functions; should make uniform
            if (sourceNode.SelectSingleNode("signalid") != null)
            {
                ID = sourceNode.SelectSingleNode("signalid").InnerText;
                ActionType = (ActionType)Enum.Parse(typeof(ActionType), sourceNode.SelectSingleNode("action").InnerText);
                Quantity = C2Service.SafeParseDecimal(sourceNode.SelectSingleNode("quant").InnerText);
                Symbol = sourceNode.SelectSingleNode("symbol").InnerText;

                if (sourceNode.SelectSingleNode("filledwhen") != null)
                    Traded = C2Service.SafeParseDate(sourceNode.SelectSingleNode("filledwhen").InnerText);

                Posted = C2Service.SafeParseDate(sourceNode.SelectSingleNode("postedwhen").InnerText);
                TimeInForce = (TimeInForce)Enum.Parse(typeof(TimeInForce), sourceNode.SelectSingleNode("TIF").InnerText);
                SecurityType = (SecurityType)Enum.Parse(typeof(SecurityType), sourceNode.SelectSingleNode("instrument").InnerText, true);
                Limit = C2Service.SafeParseDecimal(sourceNode.SelectSingleNode("limitPrice").InnerText);
                Stop = C2Service.SafeParseDecimal(sourceNode.SelectSingleNode("stopPrice").InnerText);
                Comment = sourceNode.SelectSingleNode("commentary").InnerText;

                if (sourceNode.SelectSingleNode("fillprice") != null)
                    TradePrice = C2Service.SafeParseDecimal(sourceNode.SelectSingleNode("fillprice").InnerText);

                if (sourceNode.SelectSingleNode("tradeid") != null)
                    TradeID = sourceNode.SelectSingleNode("tradeid").InnerText;

                IsMarketOrder = sourceNode.SelectSingleNode("marketOrder").InnerText == "1";
              //<conditionalUpon></conditionalUpon>
            }
            else if (sourceNode.SelectSingleNode("sigid") != null)
            {
                ID = sourceNode.SelectSingleNode("sigid").InnerText;
                Posted = C2Service.SafeParseDate(sourceNode.SelectSingleNode("posted").InnerText);
                Traded = C2Service.SafeParseDate(sourceNode.SelectSingleNode("traded").InnerText);
                ActionType = (ActionType)Enum.Parse(typeof(ActionType), sourceNode.SelectSingleNode("action").InnerText);
                Quantity = C2Service.SafeParseDecimal(sourceNode.SelectSingleNode("quant").InnerText);
                Symbol = sourceNode.SelectSingleNode("symbol").InnerText;
                SecurityType = (SecurityType)Enum.Parse(typeof(SecurityType), sourceNode.SelectSingleNode("type").InnerText, true);
                Limit = C2Service.SafeParseDecimal(sourceNode.SelectSingleNode("limit").InnerText);
                Stop = C2Service.SafeParseDecimal(sourceNode.SelectSingleNode("stop").InnerText);
                TimeInForce = (TimeInForce)Enum.Parse(typeof(TimeInForce), sourceNode.SelectSingleNode("tif").InnerText);
                TradePrice = C2Service.SafeParseDecimal(sourceNode.SelectSingleNode("tradeprice").InnerText);
                Comment = sourceNode.SelectSingleNode("comment").InnerText;

                IsMarketOrder = Limit <= 0 && Stop <= 0;
            }
            else
                throw new Exception("Unrecognized signal node XML: " + sourceNode.OuterXml);
        }
    }
}
